package lab_15.com.acme.bankapp.domain.bank;

import lab_15.com.acme.bankapp.domain.bank.Email.EmailService;
import lab_15.com.acme.bankapp.domain.bank.Exceptions.ClientExistsException;

import java.io.Serializable;
import java.util.*;

public class Bank implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5451507215178922650L;
	private Map<String, Client> clients = new HashMap<String, Client>();
	private HashSet<ClientRegistrationListener> listeners;

	public Bank() {
		super();
		this.listeners = new HashSet<ClientRegistrationListener>();
	}

	public Bank(HashSet<ClientRegistrationListener> listeners) {
		super();
		this.listeners = listeners;
		this.listeners.add(new Listeners.EmailNotificationListener());
	}

	public static class Listeners {

		public static class EmailNotificationListener implements ClientRegistrationListener,
				Serializable {
			private static final long serialVersionUID = -5342434879251617457L;

			@Override
			public void onClientAdded(Client client) {
				EmailService.sendNotificationEmail(client);
			}
		}

		public static class PrintClientListener implements ClientRegistrationListener, Serializable {

			private static final long serialVersionUID = 7832357213038684324L;

			@Override
			public void onClientAdded(Client c) {
				c.printAllClientData();

			}

		}

		@SuppressWarnings("unused")
		private static class DebugClientListener implements ClientRegistrationListener, Serializable {

			private static final long serialVersionUID = -5782044084369700714L;

			@Override
			public void onClientAdded(Client c) {
				System.out.format("Print debug info on client %1$s %2$s.\n", c.getClientSalutation(),
						c.getName());

			}

		}

	}

	public void addListener(ClientRegistrationListener listener) {
		listeners.add(listener);
	}

	public boolean clientExists(String name) {
		return clients.containsKey(name);
	}

	public Client getClientByName(String name) {
		return clients.get(name);
	}

	/**
	 * @param client
	 * @return Added client
	 * @throws ClientExistsException
	 */
	public Client addClient(Client client) throws ClientExistsException {
		if (clientExists(client.getName())) {
			throw new ClientExistsException();
		}

		clients.put(client.getName(), client);

		for (ClientRegistrationListener listener : listeners) {
			listener.onClientAdded(client);
		}
		return client;
	}

	/**
	 * Add a client, if they haven't already been added.</br> Returns the
	 * existing client if they are already among the clients of the bank.
	 * 
	 * @throws ClientExistsException
	 */
	public Client updateClient(Gender gender, String name) {
		if (clientExists(name)) {
			return getClientByName(name);
		} else {
			Client client = new Client(gender, name);
			try {
				return addClient(client);
			} catch (ClientExistsException e) {
				return getClientByName(name);
			}
		}

	}

	private Collection<Client> getClients() {
		return clients.values();
	}

	/**
	 * Get all bank data to write to file.
	 */
	public String getBankStreamData() {

		StringBuilder result = new StringBuilder();
		boolean first = true;
		for (Client client : getClients()) {
			if (first) {
				first = false;
			} else {
				result.append("\n");
			}
			result.append(client.getClientStreamData());
		}
		return result.toString();
	}

	public void printBankData() {
		System.out.println(this);
	}

	@Override
	public String toString() {
		StringBuilder result = new StringBuilder();
		for (Client client : getClients()) {
			result.append(client);
		}
		return result.toString();
	}
}
